﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DevOnServer
{
    public abstract class CMover : CWorldObject
    {
        public CMover(int id, CWorld world, CMoverProp prop)
            : base(id, world)
        {
            MoverProp = prop;

            if (prop != null)
            {
                Size = prop.Size;
                Speed = prop.Speed;
            }
        }

        public CWorldObject Followed;

        public CMoverProp MoverProp { get; private set; }

        public short Speed = 100;

        public CVec3Df TargetPos;

        protected int m_nextPosUpdate;

        public bool IsMoving
        {
            get
            {
                return m_nextPosUpdate != 0;
            }
        }

        public void walk(CVec3Df pos)
        {
            Followed = null;

            TargetPos = pos;
            m_nextPosUpdate = s_time + 500;

            if (Type == ObjType.Player)
            {
                World.sendToLocalArea(this, CPacketCreator.objectWalking(this), (CPlayerObject)this);

                // calcul de la rotation
                float totalX = Position.X - TargetPos.X;
                float totalZ = Position.Z - TargetPos.Z;
                if (totalZ < float.Epsilon && totalZ > -float.Epsilon && totalX < float.Epsilon && totalX > -float.Epsilon)
                {
                    Rotation = 0;
                }
                else
                {
                    float angle = (float)((Math.Atan2(totalZ, totalX) * 180 / Math.PI) + 90D);
                    if (angle < 0)
                        angle = 360 + angle;
                    if (Position.X >= TargetPos.X)
                        angle += 180;
                    else
                        angle -= 180;
                    if (angle >= 360)
                        angle -= 360;

                    Rotation = (short)(angle * 10.0f);
                }
            }
            else
            {
                World.sendToLocalArea(this, CPacketCreator.objectWalking(this));
            }
        }

        public void follow(CWorldObject obj)
        {
            Followed = obj;

            if (obj != null)
            {
                TargetPos.X = obj.Position.X;
                TargetPos.Y = Position.Y;
                TargetPos.Z = obj.Position.Z;

                m_nextPosUpdate = s_time + 500;

                if (Type == ObjType.Player)
                {
                    World.sendToLocalArea(this, CPacketCreator.follow(this), (CPlayerObject)this);
                }
                else
                {
                    World.sendToLocalArea(this, CPacketCreator.follow(this));
                }
            }
        }

        protected void _updatePosition()
        {
            if (m_nextPosUpdate != 0 && s_time >= m_nextPosUpdate)
            {
                if (Followed != null && (Followed.Type == ObjType.Player || Followed.Type == ObjType.Monster))
                {
                    TargetPos.X = Followed.Position.X;
                    TargetPos.Y = Position.Y;
                    TargetPos.Z = Followed.Position.Z;
                }

                CVec3Df speed = TargetPos - Position;
                float length = speed.Length;

                if (length - 0.000001f < 0.0f && length + 0.000001f > 0.0f)
                {
                    m_nextPosUpdate = 0;
                    Position = TargetPos;
                }
                else
                {
                    speed /= length;

                    int negativity =
                        (Position.X < TargetPos.X ? 1 : 0) |
                        (Position.Y < TargetPos.Y ? 1 : 0) << 1 |
                        (Position.Z < TargetPos.Z ? 1 : 0) << 2;

                    Position += speed * (float)(s_time - m_nextPosUpdate + 500) *
                        (1.0f / 10000.0f) * Speed;

                    m_nextPosUpdate = s_time + 500;

                    if (negativity != (
                        (Position.X < TargetPos.X ? 1 : 0) |
                        (Position.Y < TargetPos.Y ? 1 : 0) << 1 |
                        (Position.Z < TargetPos.Z ? 1 : 0) << 2))
                    {
                        m_nextPosUpdate = 0;
                        Position = TargetPos;
                    }
                }

                onChangePosition();
            }
        }
    }
}